const fs = require('fs');
const path = require('path')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default; // 遍历
const babel = require('@babel/core')

function stepOne(filename) {
    const content = fs.readFileSync(filename, 'utf-8');
    console.log(content);
    // 选择合适的数据结构 ，AST 抽象语法树
    const ast = parser.parse(content, {
        sourceType: 'module'
    })
    // console.log(ast)
    // 处理依赖关系
    const dependencies = {}
    traverse(ast, {
        ImportDeclaration({ node }) {
            // console.log(node)
            const dirname = path.dirname(filename)
            // console.log(dirname)
            const newFile = './' + path.join(dirname, node.source.value);
            dependencies[node.source.value] = newFile;
        }
    })

    console.log(dependencies);
    const { code } = babel.transformFromAst(ast, null, {
        presets: ["@babel/preset-env"]
    })
    // console.log(code)
    return {
        filename,
        dependencies,
        code
    }
}

function stepTwo(entry) {
    // 入口文件模型
    const entryModel = stepOne(entry)
    const graphArray = [entryModel];
    for (let i = 0; i < graphArray.length; i++) {
        const item = graphArray[i];
        const { dependencies } = item;
        for (let j in dependencies) {
            graphArray.push(
                stepOne(dependencies[j])
            )
        }
    }

    // console.log(graphArray)
    const graph = {};
    graphArray.forEach(item => {
        graph[item.filename] = {
            dependencies: item.dependencies,
            code: item.code
        }
    })

    return graph;
}

function step3(entry) {
    const graph = JSON.stringify(stepTwo(entry));
    return `
        (function(graph) {
            //require函数的本质是执行一个模块的代码，然后将相应变量挂载到exports对象上
            function require(module) {
                //localRequire的本质是拿到依赖包的exports变量
                function localRequire(relativePath) {
                    return require(graph[module].dependencies[relativePath]);
                }
                var exports = {};
                (function(require, exports, code) {
                    // code 依赖的其他模块的在exports中
                    eval(code);
                })(localRequire, exports, graph[module].code);
                return exports;//函数返回指向局部变量，形成闭包，exports变量在函数执行后不会被摧毁
            }
            require('${entry}')
        })(${graph})`
}

const code = step3('./src/index.js');

console.log(code)